# -*- coding: utf-8 -*-
import time
import re
import os
import threading
import paramiko
import hashlib
from time import sleep
from gglobal import logger

class Server(object):

    def __init__(self, ip="", port=22, username="", password="", timeout=30):
        """
        通过IP, 端口，用户名，密码，超时时间，初始化一个远程主机
        :param str ip:
        :param int port: default value is 22
        :param str username:
        :param str password:
        :param int timeout: default value is 30.
        """
        self.logger = logger

        # 连接信息
        self._ip: str = ip
        self._port: int = port
        self._username: str = username
        self._password: str = password
        self._timeout: int = timeout
        # transport, channel, ssh, sftp, prompt
        self._transport = None
        self._channel = None
        self._ssh = None
        self._sftp = None
        self._prompt = None
        # 连接失败的重试次数（总计3次尝试）
        self._try_times = 2

    @staticmethod
    def remove_ansi_colors(text):
        """
        去除字符串中的ANSI颜色代码
        Args:
            text (str): 包含ANSI颜色代码的字符串
        Returns:
            str: 去除颜色代码后的纯文本字符串
        """
        # ANSI颜色代码的正则表达式模式
        # 匹配 \x1b[...m 或 \033[...m 格式的ANSI转义序列
        ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
        return ansi_escape.sub('', text)

    # 调用connect方法连接远程主机
    def connect(self):
        """
        :return: result
        """
        import socket
        _result = ""
        while True:
            # 尝试连接
            try:
                self._transport = paramiko.Transport((self._ip, self._port))
                
                # 启用TCP Keep-Alive机制
                try:
                    sock = self._transport.sock
                    if sock:
                        # 启用TCP Keep-Alive
                        sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
                        
                        # 在Windows和Linux上设置Keep-Alive参数
                        if hasattr(socket, 'TCP_KEEPIDLE'):
                            # Linux: 开始发送keep-alive探测前的空闲时间（秒）
                            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 30)
                        if hasattr(socket, 'TCP_KEEPINTVL'):
                            # Linux: keep-alive探测间隔（秒）
                            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 5)
                        if hasattr(socket, 'TCP_KEEPCNT'):
                            # Linux: 失败的keep-alive探测次数
                            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)
                        
                        self.logger.debug(f"已为{self._ip}启用TCP Keep-Alive")
                except Exception as e:
                    self.logger.warning(f"设置TCP Keep-Alive失败: {e}")
                
                # 设置transport的keep-alive（SSH层面的心跳）
                self._transport.set_keepalive(30)  # 每30秒发送SSH keep-alive包
                
                self._transport.connect(
                    username=self._username, password=self._password
                )
                # 如果没有抛出异常说明连接成功，直接返回
                _result += "%s 创建成功" % self._ip
                break
            # 这里对可能的异常如网络不通、链接超时、socket.error, socket.timeout直接输出
            except Exception as _e:
                if self._try_times != 0:
                    _result += "第%i次连接 %s 异常，原因：%s\n" % (
                        3 - self._try_times,
                        self._ip,
                        _e,
                    )
                    _result += "进行重试\n"
                    self._try_times -= 1
                else:
                    _result += "第%i次连接 %s 异常，原因：%s\n" % (
                        3 - self._try_times,
                        self._ip,
                        _e,
                    )
                    _result += "连接远程主机 %s 失败，结束重试" % self._ip
                    break
        return _result

    # 开启ssh，直接执行时使用
    def open_ssh(self):
        # 连接ssh
        try:
            self._ssh = paramiko.SSHClient()
            # self._ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self._ssh._transport = self._transport
            return "%s ssh连接成功" % self._ip
        except Exception as _e:
            return "%s ssh连接失败：%s" % (self._ip, _e)

    # ssh发送无需交互的单条命令
    def ssh_send_cmd(self, cmd):
        """
        仅支持无需交互的指令
        :param str cmd:
        :return: str stdout、str stderr
        """
        try:
            _stdin, _stdout, _stderr = self._ssh.exec_command(cmd)
            for outmessage in self.line_buffered(_stdout):
                self.logger.info(outmessage.strip())
            # 返回decode的指令stdout和stderr信息
            # return _stdout.read().decode(), _stderr.read().decode()
        except Exception as _e:
            return "ssh指令执行失败：%s" % _e

    def line_buffered(self, f):
        """
        按行读取文件内容的生成器函数
        Args:
            f: 文件对象
        Yields:
            str: 读取的行内容
        """
        line_buf = ""
        while not f.channel.exit_status_ready():
            try:
                chunk = f.read(size=1).decode("utf-8", "ignore")
                line_buf += chunk
                if line_buf.endswith("\n"):
                    yield line_buf
                    line_buf = ""
            except Exception as e:
                self.logger.error(f"读取错误: {e}")
                break

    # 开启sftp
    def open_sftp(self):
        # 连接sftp
        try:
            self._sftp = paramiko.SFTPClient.from_transport(self._transport)
            return "%s sftp连接成功" % self._ip
        except Exception as _e:
            return "%s sftp连接失败：%s" % (self._ip, _e)

    # sftp get单个文件（原始版本，保持兼容性）
    def sftp_get(self, remotefile="", localfile=""):
        """
        :param str remotefile: 远端的绝对路径+文件名
        :param str localfile: 本地的绝对路径+文件名
        :return: 下载结果
        """
        try:
            self._sftp.get(remotefile, localfile)
            return "%s下载成功" % remotefile
        except Exception as e:
            return "%s下载失败：%s" % (remotefile, e)

    # sftp put单个文件（原始版本，保持兼容性）
    def sftp_put(self, localfile="", remotefile=""):
        """
        :param str localfile: 本地的绝对路径+文件名
        :param str remotefile: 远端的绝对路径+文件名
        :return: 上传结果
        """
        try:
            self._sftp.put(localfile, remotefile)
            return "%s上传成功" % localfile
        except Exception as e:
            return "%s上传失败：%s" % (localfile, e)

    # 优化版本：支持带宽监控、分块传输、断点续传的下载
    def sftp_get_advanced(self, remotefile="", localfile="", chunk_size=32768, resume=True, progress_callback=None, max_retries=3):
        """
        高级SFTP下载，支持带宽监控、分块传输、断点续传、文件完整性检查
        :param str remotefile: 远端的绝对路径+文件名
        :param str localfile: 本地的绝对路径+文件名
        :param int chunk_size: 分块大小（字节），默认32KB
        :param bool resume: 是否支持断点续传
        :param function progress_callback: 进度回调函数，参数为(已传输字节, 总字节, 传输速度)
        :param int max_retries: 最大重试次数
        :return: dict 包含结果信息的字典
        """
        for retry_count in range(max_retries):
            try:
                # 获取远程文件大小
                remote_stat = self._sftp.stat(remotefile)
                total_size = remote_stat.st_size
                
                # 检查本地文件是否存在且完整性
                local_size = 0
                file_corrupted = False
                
                if resume and os.path.exists(localfile):
                    local_size = os.path.getsize(localfile)
                    
                    # 检查文件是否为空或损坏
                    if local_size == 0:
                        file_corrupted = True
                        self.logger.warning(f"本地文件{localfile}为空，将重新下载")
                    elif local_size > total_size:
                        file_corrupted = True
                        self.logger.warning(f"本地文件{localfile}大小异常，将重新下载")
                    elif local_size == total_size:
                        # 文件大小相同，进行简单的完整性检查
                        if self._verify_file_integrity(localfile, total_size):
                            # 发送100%进度回调
                            if progress_callback:
                                progress_callback(total_size, total_size, 0)
                            
                            return {
                                'success': True,
                                'message': f"{remotefile}已完整下载",
                                'total_size': total_size,
                                'transferred': total_size,
                                'speed': 0,
                                'elapsed_time': 0
                            }
                        else:
                            file_corrupted = True
                            self.logger.warning(f"本地文件{localfile}完整性检查失败，将重新下载")
                
                # 如果文件损坏，删除并重新开始
                if file_corrupted and os.path.exists(localfile):
                    try:
                        os.remove(localfile)
                        local_size = 0
                        self.logger.info(f"已删除损坏的本地文件{localfile}")
                    except Exception as e:
                        self.logger.error(f"删除损坏文件失败: {e}")
                
                # 创建本地目录
                os.makedirs(os.path.dirname(localfile), exist_ok=True)
                
                # 开始传输
                start_time = time.time()
                transferred = local_size
                last_progress_time = start_time
                last_transferred = local_size
                
                with self._sftp.open(remotefile, 'rb') as remote_file:
                    # 如果是断点续传，跳到指定位置
                    if local_size > 0:
                        remote_file.seek(local_size)
                    
                    with open(localfile, 'ab' if (resume and local_size > 0) else 'wb') as local_file:
                        while transferred < total_size:
                            # 计算本次读取大小
                            remaining = total_size - transferred
                            current_chunk_size = min(chunk_size, remaining)
                            
                            # 读取数据块
                            chunk = remote_file.read(current_chunk_size)
                            if not chunk:
                                break
                            
                            # 写入本地文件并立即刷新
                            local_file.write(chunk)
                            local_file.flush()
                            os.fsync(local_file.fileno())  # 强制写入磁盘
                            transferred += len(chunk)
                            
                            # 计算传输速度（每秒更新一次）
                            current_time = time.time()
                            if current_time - last_progress_time >= 1.0:
                                elapsed_time = current_time - start_time
                                speed = (transferred - local_size) / elapsed_time if elapsed_time > 0 else 0
                                
                                # 调用进度回调
                                if progress_callback:
                                    progress_callback(transferred, total_size, speed)
                                
                                last_progress_time = current_time
                                last_transferred = transferred
                
                # 最终完整性检查
                if transferred == total_size and self._verify_file_integrity(localfile, total_size):
                    elapsed_time = time.time() - start_time
                    avg_speed = (transferred - local_size) / elapsed_time if elapsed_time > 0 else 0
                    
                    # 发送最终的100%进度回调
                    if progress_callback:
                        progress_callback(transferred, total_size, avg_speed)
                    
                    return {
                        'success': True,
                        'message': f"{remotefile}下载成功",
                        'total_size': total_size,
                        'transferred': transferred,
                        'speed': avg_speed,
                        'elapsed_time': elapsed_time
                    }
                else:
                    raise Exception("文件传输不完整或完整性检查失败")
                    
            except Exception as e:
                error_msg = str(e)
                self.logger.error(f"下载尝试 {retry_count + 1}/{max_retries} 失败: {error_msg}")
                
                # 如果是网络相关错误，删除可能损坏的部分文件
                if "Garbage packet received" in error_msg or "Connection lost" in error_msg or "Socket is closed" in error_msg:
                    if os.path.exists(localfile):
                        try:
                            os.remove(localfile)
                            self.logger.info(f"网络错误，已删除可能损坏的文件{localfile}")
                        except Exception:
                            pass
                
                # 如果不是最后一次重试，等待后重试
                if retry_count < max_retries - 1:
                    wait_time = (retry_count + 1) * 2  # 递增等待时间
                    self.logger.info(f"等待{wait_time}秒后重试...")
                    time.sleep(wait_time)
                    
                    # 重新建立连接
                    try:
                        self._sftp.close()
                        self.open_sftp()
                    except Exception:
                        pass
                else:
                    # 最后一次重试失败，返回错误
                    return {
                        'success': False,
                        'message': f"{remotefile}下载失败：{error_msg}",
                        'total_size': 0,
                        'transferred': 0,
                        'speed': 0,
                        'elapsed_time': 0
                    }
        
        # 理论上不会到达这里
        return {
            'success': False,
            'message': f"{remotefile}下载失败：超过最大重试次数",
            'total_size': 0,
            'transferred': 0,
            'speed': 0,
            'elapsed_time': 0
        }

    # 优化版本：支持带宽监控、分块传输、断点续传的上传
    def sftp_put_advanced(self, localfile="", remotefile="", chunk_size=32768, resume=True, progress_callback=None, max_retries=3):
        """
        高级SFTP上传，支持带宽监控、分块传输、断点续传、文件完整性检查
        :param str localfile: 本地的绝对路径+文件名
        :param str remotefile: 远端的绝对路径+文件名
        :param int chunk_size: 分块大小（字节），默认32KB
        :param bool resume: 是否支持断点续传
        :param function progress_callback: 进度回调函数，参数为(已传输字节, 总字节, 传输速度)
        :param int max_retries: 最大重试次数
        :return: dict 包含结果信息的字典
        """
        # 检查本地文件是否存在
        if not os.path.exists(localfile):
            return {
                'success': False,
                'message': f"本地文件{localfile}不存在",
                'total_size': 0,
                'transferred': 0,
                'speed': 0,
                'elapsed_time': 0
            }
        
        # 获取本地文件大小并检查完整性
        total_size = os.path.getsize(localfile)
        if total_size == 0:
            return {
                'success': False,
                'message': f"本地文件{localfile}为空",
                'total_size': 0,
                'transferred': 0,
                'speed': 0,
                'elapsed_time': 0
            }
        
        if not self._verify_file_integrity(localfile, total_size):
            return {
                'success': False,
                'message': f"本地文件{localfile}完整性检查失败",
                'total_size': 0,
                'transferred': 0,
                'speed': 0,
                'elapsed_time': 0
            }
        
        for retry_count in range(max_retries):
            try:
                # 检查远程文件是否存在且完整性
                remote_size = 0
                file_corrupted = False
                
                if resume:
                    try:
                        remote_stat = self._sftp.stat(remotefile)
                        remote_size = remote_stat.st_size
                        
                        # 检查远程文件是否为空或损坏
                        if remote_size == 0:
                            file_corrupted = True
                            self.logger.warning(f"远程文件{remotefile}为空，将重新上传")
                        elif remote_size > total_size:
                            file_corrupted = True
                            self.logger.warning(f"远程文件{remotefile}大小异常，将重新上传")
                        elif remote_size == total_size:
                            # 文件大小相同，认为已完整上传
                            # 发送100%进度回调
                            if progress_callback:
                                progress_callback(total_size, total_size, 0)
                            
                            return {
                                'success': True,
                                'message': f"{localfile}已完整上传",
                                'total_size': total_size,
                                'transferred': total_size,
                                'speed': 0,
                                'elapsed_time': 0
                            }
                    except FileNotFoundError:
                        remote_size = 0
                
                # 如果远程文件损坏，删除并重新开始
                if file_corrupted:
                    try:
                        self._sftp.remove(remotefile)
                        remote_size = 0
                        self.logger.info(f"已删除损坏的远程文件{remotefile}")
                    except Exception as e:
                        self.logger.error(f"删除损坏的远程文件失败: {e}")
                        remote_size = 0
                
                # 开始传输
                start_time = time.time()
                transferred = remote_size
                last_progress_time = start_time
                last_transferred = remote_size
                
                with open(localfile, 'rb') as local_file:
                    # 如果是断点续传，跳到指定位置
                    if remote_size > 0:
                        local_file.seek(remote_size)
                    
                    with self._sftp.open(remotefile, 'ab' if (resume and remote_size > 0) else 'wb') as remote_file:
                        while transferred < total_size:
                            # 计算本次读取大小
                            remaining = total_size - transferred
                            current_chunk_size = min(chunk_size, remaining)
                            
                            # 读取数据块
                            chunk = local_file.read(current_chunk_size)
                            if not chunk:
                                break
                            
                            # 写入远程文件并立即刷新
                            remote_file.write(chunk)
                            remote_file.flush()
                            transferred += len(chunk)
                            
                            # 计算传输速度（每秒更新一次）
                            current_time = time.time()
                            if current_time - last_progress_time >= 1.0:
                                elapsed_time = current_time - start_time
                                speed = (transferred - remote_size) / elapsed_time if elapsed_time > 0 else 0
                                
                                # 调用进度回调
                                if progress_callback:
                                    progress_callback(transferred, total_size, speed)
                                
                                last_progress_time = current_time
                                last_transferred = transferred
                
                # 最终完整性检查
                if transferred == total_size:
                    # 验证远程文件大小
                    try:
                        final_remote_stat = self._sftp.stat(remotefile)
                        if final_remote_stat.st_size == total_size:
                            elapsed_time = time.time() - start_time
                            avg_speed = (transferred - remote_size) / elapsed_time if elapsed_time > 0 else 0
                            
                            # 发送最终的100%进度回调
                            if progress_callback:
                                progress_callback(transferred, total_size, avg_speed)
                            
                            return {
                                'success': True,
                                'message': f"{localfile}上传成功",
                                'total_size': total_size,
                                'transferred': transferred,
                                'speed': avg_speed,
                                'elapsed_time': elapsed_time
                            }
                        else:
                            raise Exception(f"远程文件大小验证失败: 期望{total_size}, 实际{final_remote_stat.st_size}")
                    except Exception as e:
                        raise Exception(f"上传后验证失败: {e}")
                else:
                    raise Exception("文件传输不完整")
                    
            except Exception as e:
                error_msg = str(e)
                self.logger.error(f"上传尝试 {retry_count + 1}/{max_retries} 失败: {error_msg}")
                
                # 如果是网络相关错误，删除可能损坏的远程文件
                if "Garbage packet received" in error_msg or "Connection lost" in error_msg or "Socket is closed" in error_msg:
                    try:
                        self._sftp.remove(remotefile)
                        self.logger.info(f"网络错误，已删除可能损坏的远程文件{remotefile}")
                    except Exception:
                        pass
                
                # 如果不是最后一次重试，等待后重试
                if retry_count < max_retries - 1:
                    wait_time = (retry_count + 1) * 2  # 递增等待时间
                    self.logger.info(f"等待{wait_time}秒后重试...")
                    time.sleep(wait_time)
                    
                    # 重新建立连接
                    try:
                        self._sftp.close()
                        self.open_sftp()
                    except Exception:
                        pass
                else:
                    # 最后一次重试失败，返回错误
                    return {
                        'success': False,
                        'message': f"{localfile}上传失败：{error_msg}",
                        'total_size': 0,
                        'transferred': 0,
                        'speed': 0,
                        'elapsed_time': 0
                    }
        
        # 理论上不会到达这里
        return {
            'success': False,
            'message': f"{localfile}上传失败：超过最大重试次数",
            'total_size': 0,
            'transferred': 0,
            'speed': 0,
            'elapsed_time': 0
        }

    def _verify_file_integrity(self, filepath, expected_size):
        """
        验证文件完整性
        :param str filepath: 文件路径
        :param int expected_size: 期望的文件大小
        :return: bool 文件是否完整
        """
        try:
            if not os.path.exists(filepath):
                return False
            
            # 检查文件大小
            actual_size = os.path.getsize(filepath)
            if actual_size != expected_size:
                self.logger.warning(f"文件{filepath}大小不匹配: 期望{expected_size}, 实际{actual_size}")
                return False
            
            # 检查文件是否可读
            try:
                with open(filepath, 'rb') as f:
                    # 读取文件开头和结尾的一小部分来验证文件可读性
                    f.read(min(1024, actual_size))
                    if actual_size > 1024:
                        f.seek(-1024, 2)  # 从文件末尾向前1024字节
                        f.read(1024)
                return True
            except Exception as e:
                self.logger.error(f"文件{filepath}读取测试失败: {e}")
                return False
                
        except Exception as e:
            self.logger.error(f"文件{filepath}完整性检查失败: {e}")
            return False

    # 格式化传输速度显示
    def format_speed(self, speed_bytes_per_sec):
        """
        格式化传输速度显示
        :param float speed_bytes_per_sec: 每秒传输字节数
        :return: str 格式化后的速度字符串
        """
        if speed_bytes_per_sec < 1024:
            return f"{speed_bytes_per_sec:.2f} B/s"
        elif speed_bytes_per_sec < 1024 * 1024:
            return f"{speed_bytes_per_sec / 1024:.2f} KB/s"
        elif speed_bytes_per_sec < 1024 * 1024 * 1024:
            return f"{speed_bytes_per_sec / (1024 * 1024):.2f} MB/s"
        else:
            return f"{speed_bytes_per_sec / (1024 * 1024 * 1024):.2f} GB/s"

    # 格式化文件大小显示
    def format_size(self, size_bytes):
        """
        格式化文件大小显示
        :param int size_bytes: 文件大小（字节）
        :return: str 格式化后的大小字符串
        """
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.2f} KB"
        elif size_bytes < 1024 * 1024 * 1024:
            return f"{size_bytes / (1024 * 1024):.2f} MB"
        else:
            return f"{size_bytes / (1024 * 1024 * 1024):.2f} GB"

    # 开启channel
    def open_channel(self):
        """
        :return: result
        """
        _result = ""
        try:
            self._channel = self._transport.open_session()
            self._channel.settimeout(self._timeout)
            self._channel.get_pty()
            self._channel.invoke_shell()
            # 如果没有抛出异常说明连接成功
            _result += "%s channel建立成功" % self._ip
            sleep(0.5)  # 减少等待时间，提高响应性
            _Banner = self._channel.recv(65535)  # 接收ssh banner信息
        except Exception as _e:
            _result += "%s channel建立失败：%s" % (self._ip, _e)
        return _result

    # 获取channel提示符
    def get_prompt(self, expect_symbol=""):
        """
        :param str expect_symbol: The prompt's symbol,like '>','# ','$ ',etc.
        :return: result
        """
        _result = ""
        try:
            # 发送"Enter"获取提示符
            n = 0
            while n < 3:
                self._channel.send("\r")
                # 减少等待时间，提高响应性
                sleep(0.3)
                _Prompt_vendor = self._channel.recv(64)
                # 获取提示符的两种方式：
                # 1. 按\r\n进行字符串分割，后边的就是完整的提示符
                # self._prompt = _Prompt_vendor.decode('utf-8').split('\r\n')[-1]
                # 2. 提示符取输出的后x位，即_Prompt_vendor[-x:]
                self._prompt = _Prompt_vendor[-2:].decode("utf-8")
                # 如果获取的提示符由期待的提示符末尾标识符结尾，判断为获取成功
                if self._prompt.endswith(expect_symbol):
                    _result += "提示符获取成功(%s)" % self._prompt
                    break
                n += 1
            else:
                _result += "提示符获取异常(%s)" % self._prompt
        except Exception as _e:
            _result += "提示符获取失败：%s" % _e
        return _result

    # 通过channel发送指令，返回执行结果。如果指令是交互指令，则需要给出交互的断点提示符
    def channel_send_cmd(
        self, cmd="", break_prompt="", long=False, timeout=15, callback=None, strip_colors=True
    ):
        """
        通过channel发送指令
        Args:
            cmd (str): 执行的指令，支持交互指令
            break_prompt (str): 判断指令结束/断点的提示符
            long (bool): 是否为长时间运行的命令
            timeout (int): 命令执行超时时间（秒），默认15秒
            callback (function): 回调函数，用于处理实时输出
            strip_colors (bool): 是否去除ANSI颜色代码，默认True
        Returns:
            str: 命令执行结果（已去除颜色代码，如果strip_colors=True）
        """
        if not cmd:
            return "命令不能为空"

        _stream = ""
        break_prompt = break_prompt or self._prompt
        start_time = time.time()

        try:
            self._channel.send(f"{cmd}\r")

            if long:
                # 长时间运行命令：在接收到提示符（break_prompt）后立即认为命令结束，避免长时间无输出仍等待到超时
                while True:
                    try:
                        if self._channel.recv_ready():
                            data = self._channel.recv(1024)
                            if not data:
                                break
                            decoded_data = data.decode("utf-8", "ignore")
                            _stream += decoded_data
                            if callback:
                                # 传入函数接收decoded_data（根据strip_colors参数决定是否去除颜色）
                                callback_data = self.remove_ansi_colors(decoded_data) if strip_colors else decoded_data
                                callback(callback_data)
                            # 当提示符重新出现，认为命令已结束（优先使用_stream判断，避免分块导致末尾匹配失败）
                            try:
                                if break_prompt and break_prompt != "None":
                                    if _stream.endswith(break_prompt) or decoded_data.strip().endswith(break_prompt):
                                        # 提示符出现，跳出循环
                                        break
                            except Exception:
                                pass
                            start_time = time.time()  # 重置超时计时器
                        elif time.time() - start_time > timeout:
                            self.logger.warning(f"命令执行超时（{timeout}秒无输出）")
                            break
                        else:
                            sleep(0.05)  # 减少等待时间，提高响应性
                    except Exception as e:
                        self.logger.error(f"读取数据错误: {e}")
                        break
            else:
                while True:
                    if self._channel.recv_ready():
                        data = self._channel.recv(1024)
                        decoded_data = data.decode("utf-8", "ignore")
                        _stream += decoded_data
                        if callback:
                            # 根据strip_colors参数决定是否去除颜色
                            callback_data = self.remove_ansi_colors(decoded_data) if strip_colors else decoded_data
                            callback(callback_data)
                        if _stream.endswith(break_prompt) or break_prompt == "None":
                            # 根据strip_colors参数决定是否去除ANSI颜色代码
                            return self.remove_ansi_colors(_stream) if strip_colors else _stream
                        start_time = time.time()  # Reset timeout timer
                    elif time.time() - start_time > timeout:
                        self.logger.warning(f"命令执行超时（{timeout}秒无输出）")
                        break
                    sleep(0.05)  # 减少等待时间，提高响应性

            # 根据strip_colors参数决定是否去除ANSI颜色代码
            return self.remove_ansi_colors(_stream) if strip_colors else _stream

        except KeyboardInterrupt:
            self.logger.info("命令被用户中断")
            self._channel.send("\x03")  # 发送Ctrl+C信号
            return "命令被中断"
        except Exception as e:
            return f"channel执行指令异常：{str(e)}"

    def is_connection_alive(self, timeout=5):
        """
        检查SSH连接是否仍然活跃
        
        Args:
            timeout (int): 检测超时时间（秒），默认5秒
            
        Returns:
            bool: 连接是否活跃
        """
        import socket
        import select
        
        try:
            # 1. 检查transport是否存在且活跃
            if not self._transport or not self._transport.is_active():
                self.logger.debug("Transport不存在或不活跃")
                return False
            
            # 2. 检查是否已认证
            if not self._transport.is_authenticated():
                self.logger.debug("Transport未认证")
                return False
            
            # 3. 检查底层socket状态
            sock = self._transport.sock
            if not sock:
                self.logger.debug("底层socket不存在")
                return False
            
            # 4. 检查socket是否可读（可能有错误数据）
            try:
                ready, _, _ = select.select([sock], [], [], 0)
                if ready:
                    # socket有数据可读，可能是错误或断开信号
                    try:
                        data = sock.recv(1, socket.MSG_PEEK | socket.MSG_DONTWAIT)
                        if not data:
                            self.logger.debug("Socket已断开（recv返回空）")
                            return False
                    except socket.error as e:
                        if e.errno in (socket.ECONNRESET, socket.ENOTCONN, socket.EBADF):
                            self.logger.debug(f"Socket错误: {e}")
                            return False
            except Exception as e:
                self.logger.debug(f"Socket状态检查异常: {e}")
            
            # 5. 主动探测：尝试执行一个轻量级命令
            try:
                # 创建临时channel进行测试
                channel = self._transport.open_channel('session')
                if channel:
                    channel.settimeout(timeout)
                    channel.exec_command('echo "connection_test"')
                    
                    # 等待命令执行并读取结果
                    response = channel.recv(1024).decode('utf-8', errors='ignore')
                    exit_status = channel.recv_exit_status()
                    channel.close()
                    
                    # 检查命令是否成功执行
                    if exit_status == 0 and 'connection_test' in response:
                        self.logger.debug("主动探测成功")
                    else:
                        self.logger.debug(f"主动探测失败: exit_status={exit_status}, response={response}")
                        return False
                else:
                    self.logger.debug("无法创建测试channel")
                    return False
                    
            except Exception as e:
                self.logger.debug(f"主动探测异常: {e}")
                return False
            
            # 6. 增强的SFTP连接检测
            # if hasattr(self, '_sftp') and self._sftp:
            #     try:
            #         # 设置SFTP超时
            #         if hasattr(self._sftp, 'get_channel'):
            #             sftp_channel = self._sftp.get_channel()
            #             if sftp_channel:
            #                 sftp_channel.settimeout(timeout)
                    
            #         # 尝试列出当前目录（更可靠的操作）
            #         self._sftp.listdir('.')
            #         self.logger.debug("SFTP连接检测成功")
            #     except Exception as e:
            #         self.logger.debug(f"SFTP连接检测失败: {e}")
            #         return False
            
            # 7. 最后检查transport的活跃状态
            try:
                # 检查transport是否活跃（替代get_stats方法）
                if hasattr(self._transport, 'is_active') and self._transport.is_active():
                    self.logger.debug("Transport连接活跃")
                elif hasattr(self._transport, 'is_authenticated') and self._transport.is_authenticated():
                    self.logger.debug("Transport连接已认证")
                else:
                    # 如果没有这些方法，尝试检查transport的基本属性
                    if self._transport and not self._transport.is_closed:
                        self.logger.debug("Transport连接正常")
                    else:
                        self.logger.debug("Transport连接可能已关闭")
                        return False
            except Exception as e:
                self.logger.debug(f"检查transport状态失败: {e}")
                # 如果检查失败，不直接返回False，继续其他检查
            
            self.logger.debug("连接状态检查通过")
            return True
            
        except Exception as e:
            self.logger.debug(f"连接检查异常: {e}")
            return False
    
    def cleanup_connection(self):
        """
        清理连接资源，在检测到连接断开时调用
        """
        try:
            self.logger.info("开始清理连接资源")
            
            # 关闭SFTP连接
            if hasattr(self, '_sftp') and self._sftp:
                try:
                    self._sftp.close()
                    self.logger.debug("SFTP连接已关闭")
                except Exception as e:
                    self.logger.warning(f"关闭SFTP连接时出错: {e}")
                finally:
                    self._sftp = None
            
            # 关闭Channel
            if hasattr(self, '_channel') and self._channel:
                try:
                    self._channel.close()
                    self.logger.debug("Channel已关闭")
                except Exception as e:
                    self.logger.warning(f"关闭Channel时出错: {e}")
                finally:
                    self._channel = None
            
            # 关闭Transport
            if hasattr(self, '_transport') and self._transport:
                try:
                    self._transport.close()
                    self.logger.debug("Transport已关闭")
                except Exception as e:
                    self.logger.warning(f"关闭Transport时出错: {e}")
                finally:
                    self._transport = None
            
            self.logger.info("连接资源清理完成")
            
        except Exception as e:
            self.logger.error(f"清理连接资源时发生异常: {e}")
    
    def reconnect(self, check_port=True, enable_ssh=True, enable_sftp=True, enable_channel=True, expect_symbol="$ "):
        """
        重新连接到远程主机 - 使用优化的connect_manage函数
        
        Args:
            check_port (bool): 是否检查端口连通性，默认True
            enable_ssh (bool): 是否开启SSH服务，默认True
            enable_sftp (bool): 是否开启SFTP服务，默认True
            enable_channel (bool): 是否开启交互式Channel，默认True
            expect_symbol (str): 期望的提示符符号，默认"$ "
            
        Returns:
            str: 重连结果信息
        """
        try:
            self.logger.info(f"开始重新连接到 {self._ip}")
            
            # 先清理现有连接
            self.cleanup_connection()
            
            # 重置重试次数
            self._try_times = 3
            
            # 使用connect_manage进行重新连接
            result = self.connect_manage(
                check=check_port,
                connect=True,
                sshopen=enable_ssh,
                sftpopen=enable_sftp,
                channel=enable_channel,
                expect_symbol=expect_symbol,
                port_timeout=5
            )
            
            if result['success']:
                success_msg = f"重新连接到 {self._ip} 成功: {result['message']}"
                self.logger.info(success_msg)
                
                # 记录详细的重连步骤结果
                for step, detail in result['details'].items():
                    self.logger.info(f"重连步骤 {step}: {detail['success']} - {detail['message']}")
                
                return success_msg
            else:
                error_msg = f"重新连接到 {self._ip} 失败: {result['message']}"
                self.logger.error(error_msg)
                
                # 记录失败的步骤详情
                for step, detail in result['details'].items():
                    if not detail['success']:
                        self.logger.error(f"重连失败步骤 {step}: {detail['message']}")
                
                return error_msg
                
        except Exception as e:
            error_msg = f"重新连接过程中发生异常: {e}"
            self.logger.error(error_msg)
            return error_msg
    
    def _websocket_check_port(self, timeout=5):
        """
        检查WebSocket端口连通性的独立函数
        
        Args:
            timeout (int): 连接超时时间（秒），默认5秒
            
        Returns:
            dict: 端口检查结果
            {
                'success': bool,  # 检查是否成功
                'message': str    # 结果消息
            }
        """
        import socket
        
        self.logger.info(f"开始检查端口连通性: {self._ip}:{self._port}")
        
        try:
            # 创建socket连接测试端口连通性
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(timeout)
            s.connect((self._ip, self._port))
            s.close()
            
            success_msg = f"端口 {self._ip}:{self._port} 连通性检查成功"
            self.logger.info(success_msg)
            
            return {
                'success': True,
                'message': success_msg
            }
            
        except socket.timeout:
            error_msg = f"端口 {self._ip}:{self._port} 连接超时（{timeout}秒）"
            self.logger.error(error_msg)
            return {
                'success': False,
                'message': error_msg
            }
            
        except ConnectionRefusedError:
            error_msg = f"端口 {self._ip}:{self._port} 连接被拒绝，目标端口可能未开放"
            self.logger.error(error_msg)
            return {
                'success': False,
                'message': error_msg
            }
            
        except OSError as e:
            error_msg = f"端口 {self._ip}:{self._port} 连通性检查失败: {str(e)}"
            self.logger.error(error_msg)
            return {
                'success': False,
                'message': error_msg
            }
            
        except Exception as e:
            error_msg = f"端口 {self._ip}:{self._port} 连通性检查异常: {str(e)}"
            self.logger.error(error_msg)
            return {
                'success': False,
                'message': error_msg
            }
     
    def connect_manage(self, check=True, connect=True, sshopen=True, sftpopen=True, channel=True, expect_symbol="$ ", port_timeout=5, cancellation_callback=None):
         """
         统一的连接管理函数，支持分步骤连接控制
         
         Args:
             check (bool): 是否检查端口连通性，默认True
             connect (bool): 是否建立SSH连接，默认True
             sshopen (bool): 是否开启SSH服务，默认True
             sftpopen (bool): 是否开启SFTP服务，默认True
             channel (bool): 是否开启交互式Channel并获取提示符，默认True
             expect_symbol (str): 期望的提示符符号，默认"$ "
             port_timeout (int): 端口连通性检查超时时间（秒），默认5秒
             cancellation_callback (function): 取消检查回调函数，返回True表示取消操作
             
         Returns:
             dict: 连接结果信息
             {
                 'success': bool,  # 整体是否成功
                 'message': str,   # 结果消息
                 'details': {      # 各步骤详细结果
                     'port_check': {'success': bool, 'message': str},
                     'connect': {'success': bool, 'message': str},
                     'ssh_open': {'success': bool, 'message': str},
                     'sftp_open': {'success': bool, 'message': str},
                     'channel_open': {'success': bool, 'message': str},
                     'prompt_get': {'success': bool, 'message': str}
                 }
             }
         """
         import socket
         
         result = {
             'success': False,
             'message': '',
             'details': {}
         }
         
         try:
             # 1. 检查端口连通性
             if check:
                 if cancellation_callback and cancellation_callback():
                     result['message'] = '连接已取消'
                     return result
                 
                 port_check_result = self._websocket_check_port(port_timeout)
                 result['details']['port_check'] = port_check_result
                 
                 if not port_check_result['success']:
                     result['message'] = port_check_result['message']
                     return result
             
             # 2. 建立SSH连接
             if connect:
                 if cancellation_callback and cancellation_callback():
                     result['message'] = '连接已取消'
                     return result
                 
                 self.logger.info(f"开始建立SSH连接: {self._ip}:{self._port}")
                 connect_result = self.connect()
                 connect_success = "创建成功" in connect_result and "失败，结束重试" not in connect_result
                 
                 result['details']['connect'] = {'success': connect_success, 'message': connect_result}
                 
                 if not connect_success or self._transport is None:
                     result['message'] = f"SSH连接失败: {connect_result}"
                     return result
             
             # 3. 开启SSH服务
             if sshopen:
                 if cancellation_callback and cancellation_callback():
                     result['message'] = '连接已取消'
                     return result
                 
                 self.logger.info("开始开启SSH服务")
                 ssh_result = self.open_ssh()
                 ssh_success = "ssh连接成功" in ssh_result
                 
                 result['details']['ssh_open'] = {'success': ssh_success, 'message': ssh_result}
                 
                 if not ssh_success:
                     result['message'] = f"SSH服务开启失败: {ssh_result}"
                     return result
             
             # 4. 开启SFTP服务
             if sftpopen:
                 if cancellation_callback and cancellation_callback():
                     result['message'] = '连接已取消'
                     return result
                 
                 self.logger.info("开始开启SFTP服务")
                 sftp_result = self.open_sftp()
                 sftp_success = "sftp连接成功" in sftp_result
                 
                 result['details']['sftp_open'] = {'success': sftp_success, 'message': sftp_result}
                 
                 if not sftp_success:
                     result['message'] = f"SFTP服务开启失败: {sftp_result}"
                     return result
             
             # 5. 开启交互式Channel
             if channel:
                 if cancellation_callback and cancellation_callback():
                     result['message'] = '连接已取消'
                     return result
                 
                 self.logger.info("开始开启交互式Channel")
                 channel_result = self.open_channel()
                 channel_success = "channel建立成功" in channel_result
                 
                 result['details']['channel_open'] = {'success': channel_success, 'message': channel_result}
                 
                 if not channel_success:
                     result['message'] = f"Channel开启失败: {channel_result}"
                     return result
                 
                 # 6. 获取提示符
                 if cancellation_callback and cancellation_callback():
                     result['message'] = '连接已取消'
                     return result
                 
                 self.logger.info(f"开始获取提示符，期望符号: {expect_symbol}")
                 prompt_result = self.get_prompt(expect_symbol=expect_symbol)
                 prompt_success = "提示符获取成功" in prompt_result
                 
                 result['details']['prompt_get'] = {'success': prompt_success, 'message': prompt_result}
                 
                 if not prompt_success:
                     result['message'] = f"提示符获取失败: {prompt_result}"
                     return result
             
             # 所有步骤都成功
             result['success'] = True
             result['message'] = f"连接到 {self._ip} 成功完成"
             self.logger.info(result['message'])
             
             return result
             
         except Exception as e:
             error_msg = f"连接管理过程中发生异常: {str(e)}"
             self.logger.error(error_msg)
             result['message'] = error_msg
             return result
     
    def get_connection_status(self):
        """
        获取详细的连接状态信息
        :return: dict 包含各个连接组件状态的字典
        """
        status = {
            'overall': False,
            'transport': False,
            'transport_active': False,
            'transport_authenticated': False,
            'channel': False,
            'channel_active': False,
            'ssh': False,
            'sftp': False,
            'ip': self._ip,
            'port': self._port,
            'username': self._username
        }
        
        try:
            # 检查transport状态
            if self._transport:
                status['transport'] = True
                status['transport_active'] = self._transport.is_active()
                status['transport_authenticated'] = self._transport.is_authenticated()
            
            # 检查channel状态
            if self._channel:
                status['channel'] = True
                status['channel_active'] = not self._channel.closed and self._channel.active
            
            # 检查ssh状态
            if self._ssh:
                status['ssh'] = True
            
            # 检查sftp状态
            if self._sftp:
                status['sftp'] = True
            
            # 综合判断整体连接状态
            status['overall'] = (status['transport'] and 
                               status['transport_active'] and 
                               status['transport_authenticated'])
            
        except Exception as e:
            self.logger.error(f"获取连接状态异常: {e}")
        
        return status

    def close(self):
        # 断开连接
        if self._ssh:
            self._ssh.close()
        if self._channel:
            self._channel.close()
        if self._transport:
            self._transport.close()
        return "%s 连接已关闭" % self._ip

    def __del__(self):
        return
